package com.jyw.system.utils;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.pagehelper.Page;
import com.jyw.common.annotation.Conversion;
import com.jyw.common.core.domain.entity.SysDictData;
import com.jyw.common.exception.ServiceException;
import com.jyw.common.utils.DictUtils;
import com.jyw.system.utils.DeptUtils;
import com.jyw.system.utils.UserUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.*;


/**
 * 主要作用是把一些int的人员信息转换成对应的name
 *
 * @author 伍绍宇
 * @date 2021/06/24
 */
@Slf4j
public class ConversionUtil {

    private final static String SET = "set";

    private final static String GET = "get";

    private final static String NAME = "ToName";

    /**
     * 首字母大写
     *
     * @param string
     */
    private static String toUpperCase4Index(String string) {
        char[] methodName = string.toCharArray();
        methodName[0] = toUpperCase(methodName[0]);
        return String.valueOf(methodName);
    }

    /**
     * 字符转成大写
     *
     * @param chars
     */
    private static char toUpperCase(char chars) {
        if (97 <= chars && chars <= 122) {
            chars ^= 32;
        }
        return chars;
    }

    /**
     * 获取get方法
     *
     * @author 伍绍宇
     * @date 2021/06/28
     */
    private static String getMethod(String name) {
        return GET + toUpperCase4Index(name);
    }


    /**
     * 返回对象
     *
     * @param obj   需要转换的数据源
     * @param clazz 回传的对象
     * @author 伍绍宇
     * @date 2021/06/28
     */
    public static <T> T conversion(Object obj, Class<T> clazz) {
        // 获取带有转换标签的参数
        T reSource = ReflectUtil.newInstance(clazz);
        Field[] fields = ReflectUtil.getFields(obj.getClass());
        for (Field field : fields) {
            Conversion annotation = field.getAnnotation(Conversion.class);
            Object fieldValue = ReflectUtil.getFieldValue(obj, field);
            String realName;
            if (annotation != null && isNotHave(reSource, realName = StrUtil.isEmpty(annotation.name()) ? (field.getName() + NAME) : annotation.name())) {
                parameterAdapter(reSource, realName, analyzeType(field, fieldValue, annotation));
            }
            if (isNotHave(reSource, field.getName())) {
                ReflectUtil.setFieldValue(reSource, field.getName(), fieldValue);
            }
        }
        return reSource;
    }

    /**
     * 参数适配器
     *
     * @author 伍绍宇
     * @date 2021/06/28
     */
    public static <T> void parameterAdapter(T reSource, String fieldName, Object fieldValue) {
        if (fieldValue == null || StrUtil.isEmpty(fieldValue.toString())) {
            return;
        }
        Class<?> type = ReflectUtil.getField(reSource.getClass(), fieldName).getType();
        // 如果类型不相同
        // 参数转换(emm..., 下次一定)
        ServiceException.assertThat(() -> type.isAssignableFrom(fieldValue.getClass()), fieldName + "字段类型异常");
        ReflectUtil.setFieldValue(reSource, fieldName, fieldValue);
    }


    /**
     * 传入需要自动转换的实体类集合
     *
     * @author 伍绍宇
     * @date 2021/06/24
     */
    public static <T> Object conversion(T obj) {
        // 获取带有转换标签的参数
        LinkedHashMap<String, Object> reSource = new LinkedHashMap<>();
        Field[] fields = ReflectUtil.getFields(obj.getClass());
        for (Field field : fields) {
            Conversion annotation = field.getAnnotation(Conversion.class);
            Object fieldValue = ReflectUtil.getFieldValue(obj, field);
            String realName;
            if (annotation != null && isNotHave(reSource, realName = StrUtil.isEmpty(annotation.name()) ? (field.getName() + NAME) : annotation.name())) {
                reSource.put(realName, analyzeType(field, fieldValue, annotation));
            }
            if (isNotHave(reSource, field.getName())) {
                reSource.put(field.getName(), fieldValue);
            }
        }
        return reSource;
    }

    /**
     * 是否已经存在有效字段
     *
     * @author 伍绍宇
     * @date 2021/06/28
     */
    private static boolean isNotHave(LinkedHashMap<String, Object> reSource, String name) {
        return reSource.get(name) == null || StrUtil.isEmpty(reSource.get(name).toString());
    }

    private static <T> boolean isNotHave(T reSource, String name) {
        Method getName = ReflectUtil.getMethodByName(reSource.getClass(), getMethod(name));
        if (getName != null) {
            Object oldValue = ReflectUtil.invoke(reSource, getName);
            return oldValue == null || StrUtil.isEmpty(oldValue.toString());
        }
        return false;
    }


    /**
     * 手动转换数组
     *
     * @author 伍绍宇
     * @date 2021/06/24
     */
    public static <T> Object conversion(List<T> obj) {
        List<Object> reList = new ArrayList<>();
        obj.forEach(data -> reList.add(conversion(data)));
        return reList;
    }

    /**
     * 手动转换数组
     *
     * @author 伍绍宇
     * @date 2021/06/24
     */
    public static List<?> conversionList(List<?> obj) {
        if(CollectionUtils.isEmpty(obj)){
            return null;
        }
        List<Object> reList = new ArrayList<>();
        obj.forEach(data -> reList.add(conversion(data)));
        if(obj instanceof Page<?>){
            Page<Object> page = (Page<Object>) obj;
            page.clear();
            page.addAll(reList);
            return page;
        }
        return reList;
    }

    /**
     * 手动转换数组
     *
     * @author 伍绍宇
     * @date 2021/06/24
     */
    public static <T> List<T> conversionList(List<?> obj, Class<T> clazz) {
        if(obj==null){
            return null;
        }
        List<T> reList = new ArrayList<>();
        obj.forEach(data -> reList.add(conversion(data, clazz)));
        if(obj instanceof Page<?>){
            Page<T> page = (Page<T>) obj;
            page.clear();
            page.addAll(reList);
            return page;
        }
        return reList;
    }


    /**
     * 手动转换集合
     *
     * @author 伍绍宇
     * @date 2021/06/24
     */
    public static <T> Object conversion(T[] obj) {
        List<Object> reList = new ArrayList<>();
        for (Object data : obj) {
            reList.add(conversion(data));
        }
        return reList;
    }


    /**
     * 解析基本数据类型
     *
     * @author 伍绍宇
     * @date 2021/06/25
     */
    private static <T> Object analyzeType(Field field, T fieldValue, Conversion conversion) {
        if (fieldValue == null) {
            return StrUtil.EMPTY;
        }
        String fieldValueStr = fieldValue.toString();
        // 是不是集合
        if (List.class.isAssignableFrom(field.getType())) {
            Collection<T> list = (Collection<T>) fieldValue;
            List<String> reList = new ArrayList<>();
            list.forEach(data -> reList.add(valueToName(conversion, data)));
            return reList;
        }
        // 是不是数组
        else if (field.getType().isArray()) {
            Object[] array = (Object[]) fieldValue;
            String[] reArray = new String[array.length];
            for (int i = 0; i < array.length; i++) {
                reArray[i] = valueToName(conversion, array[i]);
            }
            return reArray;
        }
        // 是不是逗号相连的字符串
        else if (StrUtil.isNotEmpty(fieldValueStr) && fieldValueStr.indexOf(StrUtil.COMMA) != -1) {
            StringBuilder str = new StringBuilder();
            String[] datas = fieldValueStr.split(StrUtil.COMMA);
            for (String data : datas) {
                str.append(",").append(valueToName(conversion, data));
            }
            return str.substring(1);
        }
        return valueToName(conversion, fieldValue);
    }

    /**
     * 转换参数核心
     *
     * @param conversion 字段上的标签
     * @param value      字段值
     * @author 伍绍宇
     * @date 2021/06/24
     */
    private static String valueToName(Conversion conversion, Object value) {
        String reSource = StrUtil.EMPTY;
        if (value == null || StrUtil.isEmpty(value.toString())) {
            return reSource;
        }
        switch (conversion.value()) {
            case DICT:
                List<SysDictData> dictCache = DictUtils.getDictCache(conversion.dictType());
                if(!CollectionUtils.isEmpty(dictCache)){
                    String valStr;
                    if(value instanceof String){
                        valStr = (String) value;
                    }else if(value instanceof Integer){
                        valStr = ((Integer) value).toString();
                    } else if(value instanceof Long){
                        valStr = ((Long) value).toString();
                    }else {
                        valStr = null;
                    }
                    Optional<SysDictData> dictOptional = dictCache.stream().filter(data -> data.getDictValue().equals(valStr)).findFirst();
                    if(dictOptional.isPresent()){
                        reSource = dictOptional.get().getDictLabel();
                    }
                }
                break;
            case DEPT:
                reSource = DeptUtils.deptIdToName(value);
                break;
            case TEAM:
                reSource = TeamUtils.teamIdToName(value);
                break;
            default:
            case USER:
                reSource = UserUtils.userIdToName(value);
                break;
        }
        return reSource;
    }

    /**
     * 转换对象名称
     * @param objType 对象类型 1用户 2小组 3科室
     * @param objId 对象标识
     * @return
     */
    public static String getObjName(String objType,Long objId){
        if(ObjectUtils.isEmpty(objType)||ObjectUtils.isEmpty(objId)){
            return null;
        }
        switch (objType){
            case "1":
                return UserUtils.userIdToName(objId);
            case "2":
                return TeamUtils.teamIdToName(objId);
            case "3":
                return DeptUtils.deptIdToName(objId);
        }
        return objId.toString();
    }
}
